package org.springframework.boot.autoconfigure.mock.handler;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mock.annotation.MockResponse;
import org.springframework.boot.autoconfigure.mock.model.MockResMeta;
import org.springframework.boot.autoconfigure.mock.strategy.IMockResProcessor;
import org.springframework.boot.autoconfigure.mock.strategy.MockResProcessorFactory;

/**
 * @author: hooware
 * @Date: 2021/12/26 18:19
 * @Description:
 */
public class MockResponseHandler {

    private static final Logger log = LoggerFactory.getLogger(MockResponseHandler.class);

    @Autowired
    private MockResProcessorFactory mockResProcessorFactory;

    public Object process(ProceedingJoinPoint joinPoint, MockResponse mockResponse) throws Throwable {

        try {
            // 1.获取调用mock方法的返回值类型
            final MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            final Class<?> returnType = signature.getMethod().getReturnType();

            // 2.获取对应的mock response处理策略
            final IMockResProcessor mockResProcessor =
                    mockResProcessorFactory.pickMockResProcessor(mockResponse.mockResTypeEnum());
            final MockResMeta mockResMeta = this.mockResponseConvert(mockResponse, returnType);

            // 3.执行对应的mock策略
            final Object res = mockResProcessor.mockProcess(mockResMeta);
            if (res != null) {
                return res;
            }
        } catch (Exception e) {
            log.error("Mock response process fail, mock value: {}, ", mockResponse.value(), e);
        }
        // 异常或者未匹配上返回null时兜底走真正执行逻辑
        return joinPoint.proceed();
    }

    private MockResMeta mockResponseConvert(MockResponse mockResponse, Class<?> returnType) {
        final MockResMeta mockResMeta = new MockResMeta();
        mockResMeta.setValue(mockResponse.value());
        mockResMeta.setClazz(mockResponse.clazz());
        mockResMeta.setMethod(mockResponse.method());
        mockResMeta.setParams(mockResponse.params());
        mockResMeta.setReturnType(returnType);
        return mockResMeta;
    }
}
